#include <iostream>
#include <memory>
#include <vector>
#include <set>
#include <algorithm>
#include <string>
#include <list>
#include <iterator>
#include <set>

#include "Header.h"
#include "Human.h"

using std::cout;
using std::endl;
using std::string;
using std::unique_ptr;
using std::move;
using std::make_unique;

int main()
{

	//////////////////////////////////////////////////////////////////////////////////////////////
	//������� 1. unique_ptr
	{

		//1.� - ���������� ���������� ���������� ���������
		
		{
			cout << "Ex_1.a" << endl;

			std::vector<std::string*> v = { new std::string("aa"), new std::string("bb"), new std::string("cc") };
			//������������ ��� ������
			for (const auto& x : v)
			{
				cout << *x << endl;
			}
			
			for (const auto& x : v)
			{
				delete x;
			}
			__asm nop
		} //???

		//1.b - ������������� ������� 1.�:
		 //���������� ����������� std::unique_ptr: 
		 //����������� ���������� (��������� ��� ������ ������� ������������ std::unique_ptr), 
		 //���������� �������� ���������� �� ����������� ����������� ������� std::string, 
		 //���������������,
		 //� ������������ ��������
		 //
		
		{
			cout << endl << "Ex_1.b" << endl;

			std::vector<unique_ptr<string>> v/*{ make_unique<string>("aa") ,make_unique<string>("bb"),make_unique<string>("cc") }*/;//why not?
			v.push_back(make_unique<string>("aa"));
			v.push_back(make_unique<string>("bb"));
			v.push_back(make_unique<string>("cc"));
			
			//������������ ��� ������
			for (const auto& x : v)
			{
				cout << *x << endl;
			}
			
			__asm nop
			//??? ����������� ����������� ��������� ��������? - �� ���������
		} //??? ����� ������ ���������� ��� ��������� �������� ���� unique_ptr<string>

		{//1.c - ��������� ������� 1.b �������� ����������� �������� ���������� ������
		 //��������� ������� (��������, �������� ��������� �������: "AAA" -> "AAA_1")  
			cout << endl << "Ex_1.c" << endl;

			std::vector<unique_ptr<string>> v;
			v.push_back(make_unique<string>("aa"));
			v.push_back(make_unique<string>("bb"));
			v.push_back(make_unique<string>("cc"));
			
			for (auto& x : v)
			{
				cout << *x << "->";
				*x += "_1";
				cout << *x << endl;
			}

			__asm nop
		}

		{//1.d - ������������ ������ ��������	

		 //�������� unique_ptr, ������� �������� �������� ��� ������������� �������
		 //� ���������� std::string
		 //� ������� unique_ptr::operator[] ��������� ��������� ������ ����������
		 //����� ���������� ������������ ������? - �� ����������� ������
			int n = 3;
			//unique_ptr<string[]> ar = make_unique<string[]>(n);
			unique_ptr<string[], MyDeleter<string>> ar (new string[n], MyDeleter<string>(n));
			ar[0] = string("aa");
			ar[1] = string("bb");
			ar[2] = string("cc");

			cout << endl << "Ex_1.d" << endl;
			for (size_t i = 0; i < ar.get_deleter().GetN(); i++)
			{
				cout << ar[i] << endl;
			}

			__asm nop
		}

		{//1.e - ������� ������������ �������� � ���������������� delete-������� (�������)
		 //����� �������� ������ ���������� �� ����������� ��������� �������
		 //�������� unique_ptr ��� ������ �������
		 //���������� ���������������� delete-������� (�������) ��� ����������� 
		 //������������ ������
			
			std::string* arStrPtr[] = { new std::string("aa"), new std::string("bb"), new std::string("cc") };
			
			int n = sizeof(arStrPtr) / sizeof(arStrPtr[0]);
			auto deliter = [n](string** pp) 
			{for (int i = 0; i < n; i++) { delete pp[i]; } };

			unique_ptr<string*[], decltype(deliter)> ar(arStrPtr, deliter);

			//*[] **
			__asm nop
		}//����������� ���������� ������ ����� ����������� ���������� ����������������� ��������
		//��� ������ ����� �������� ����� ������ �������������

		{//1.f �������� � ��������� ������, ���������� unique_ptr ��� ���������� �� std::string
			//����������� ��������� copy() ���������� �������� ������� � ������ ������ � ���������� 
			//���� �� ����
			//���������: ������������ ��������� � ������ std::make_move_iterator
			
			std::vector<unique_ptr<string>> v;
			v.push_back(make_unique<string>("aa"));
			v.push_back(make_unique<string>("bb"));
			v.push_back(make_unique<string>("cc"));
			
			std::list<unique_ptr<string>> l;
			std::copy(std::make_move_iterator(v.begin()), std::make_move_iterator(v.end()), std::back_inserter(l));

			__asm nop
			cout << endl << "Ex_1.f_vector" << endl;
			for (const auto& x : v)
				{
				if(x) cout << *x << endl;
				else cout << "Empty" << endl;
				}
			
			
			cout << endl << "Ex_1.f_list" << endl;
			for (const auto& x : l)
			{
				cout << *x << endl;
			}
		}
		__asm nop

	}

	////////////////////////////////////////////////////////////////////////////////
	//������� 2.shared_ptr + ���������������� delete-������� 

	//����������� ����������� ������ � ���� ������ (�������) �� ������ ���������� 
	//��� ��� ��� "��������" ����� �� ������� ���������� ���� ������ � ���� � ��� �� ����,
	//������� ������������ �� ����������� ������������ ����� � ��� �� �������� ������ ������ =>
	//���������� �������� ��� ������ ��������� �������� shared_ptr
	//�. ������ �������� ������ �������/������� ���� ��� ������
	//�. ��� ��������� �������� ������ �������������� � �������������
	//�. ��������� �������� ��������� ������ ������� ����

	//���������: ����������� ������� ������ ����� � ������� ������� rand()
	
	{

	std::string s("text.txt");

	auto Deliter = [](std::ofstream* fp) {fp->close(); delete fp; };
	std::shared_ptr<std::ofstream>file(new std::ofstream(s), Deliter);
	auto file1 = file;

	for (int i = 0; i < 10; i++)
	{
		if (rand() % 2 == 1)
			*file << "writer1" << endl;
		else
			*file1 << "writer2" << endl;
	}
	
	//"��������":
	//������� writer1, writer2

	auto writer1 = file;
	auto writer2 = file1;
	
	*writer2 << "Book" << endl;

	//�������� ����� �������� ��������� ������� ��������� ������ �� "���������" �������� � ����
	//���� �������

	srand(time(0));
	if (rand() % 2 == 1)
		*writer1 << "writer1" << endl;
	else
		*writer2 << "writer2" << endl;

	__asm nop
	}//�������� �����???

	
	/***************************************************************/
	//������� 3.
	{
		//��� ������ ��������� ���� string
		std::string strings[] = { "abc", "123", "qwerty", "#$%" };
		//�� ���������� ��������� ������ ������ ������������ � ������������ ����������.
		//��������� ���������� ��������������� �������� �) ��� ����������� � �) ��� ��������� �������
		//��������� � �������!

		//� std::set "����������" �� �������� ������� ��� �����, ������� �������� ������ ����� 
		auto cmp = [](const std::shared_ptr<string> s1, const std::shared_ptr<string> s2) {return *s1 < *s2; };//���������� ��� ��������� ��������
		std::set<std::shared_ptr<string>, decltype(cmp)> set_alpha(cmp);

		int n = std::size(strings);
		for (int i = 0; i < n; i++)
		{
			/*for (const auto& el : strings)//������ �� ��������?
			{*/
			bool fl = false;
			for (auto& ch : strings[i])
			{
				if (isalpha(ch)) { fl = true; }
				else { fl = false; break; }
			}
			if (fl) set_alpha.insert(std::shared_ptr<std::string>(&strings[i], [](std::string* str) {}));
			/*}*/
		}
		
		cout << endl << "Ex_3:set_alpha" << endl;

		for (const auto& str : set_alpha)
		{
			std::cout << *str << ' ';
		}

		__asm nop
		/******************************************************************************************/

		//� std::vector "����������" ������� ��� �����, ������� �������� ������ ����� 
		//������� �� �����
		//������� �����

		std::vector<std::shared_ptr < std::string>> v_numb;
		

		for (int i = 0; i < n; i++)
		{
			bool fl = false;
			for (auto& ch : strings[i])
			{
				if (ch>='0'&& ch<='9') { fl = true; }
				else { fl = false; break; }
			}
			if (fl) v_numb.push_back(std::shared_ptr<std::string>(&strings[i], [](std::string* str) {}));
			
		}
		
		cout << endl << "Ex_3:vector_numbers" << endl;
		for (const auto& str : v_numb)
		{
			std::cout << *str << ' ';
		}
		
		int sum = 0;
		for (const auto& el : v_numb)//������ �� ��������?
		{			
			for (const auto& ch : *el)
			{
				sum += ch - '0';
			}
			
		}
		std::cout << endl << "Sum: " << sum ;
		/******************************************************************************************/
		//���� "����������" ������� ��� �����, ������� �� �������� �� �������� ����, �� �������� ����
		//� ������ �������
		
		std::vector<std::shared_ptr < std::string>> v_simb;
		
		for (int i = 0; i < n; i++)
		{
			bool fl = false;
			for (auto& ch : strings[i])
			{
				if ((ch >= '0' && ch <= '9' )|| isalpha(ch)) { fl = false; break; }
				else { fl = true; }
			}
			if (fl) v_simb.push_back(std::shared_ptr<std::string>(&strings[i], [](std::string* str) {}));

		}
		cout << endl << "Ex_3:vector_else" << endl;
		for (const auto& str : v_simb)
		{
			std::cout << *str << ' ';
		}
		__asm nop
	}


	/******************************************************************************************/
	//������� 4. 
	{
		//����:
		std::string ar[] = { "my","Hello", "World" };
		std::vector < std::shared_ptr<std::string>> v = { std::make_shared<std::string>("good"), std::make_shared<std::string>("bye") };

		int size = sizeof(ar) / sizeof(ar[0]);
		auto lambda = [](string& str) {return std::shared_ptr<std::string>(&str, [](std::string* str) {}); };
		std::transform(ar, ar + size, std::back_inserter(v), lambda);
		
		cout << endl << "Ex_4:vector<shared_ptr<string>>" << endl;
		for (const auto& str : v)
		{
			std::cout << *str << ' ';
		}

		auto cmp = [](const std::shared_ptr<string> s1, const std::shared_ptr<string> s2) {return *s1 < *s2; };
		//����� �� ���� ����������� ��� ����� ��������?
		std::sort(v.begin(), v.end(), cmp);

		//�) ��������� �������� � ������ ������� ��� ��������� �������, �� ������� �������� �������! 
		//�) ������������� ������ �� �������� � ������� �� �����
		//�) ���������� ���������� ������������ ������
		cout << endl << "Ex_4:sorted_vector<shared_ptr<string>>" << endl;
		
		for (const auto& str : v)
		{
			std::cout << *str << ' ';
		}
		cout << endl;
		__asm nop
	}
	/***************************************************************/
		//������� 5. shared_ptr � weak_ptr
		//������� ��������������� ������ ����������� ������ human. � ������ ��������:
		//��� - string
		//�������� �������: ��� ��� ��� ���...
		//�������� - shared_ptr (�������� �� ������ ��������...)
		//���� - ��������� �� weak_ptr (����� �������� ����������� ������������)

		//������ ������ human:
		//����������� - ��� ������������� ����� � ��������
		//����������� �����������, �������� ������������, move ???
		//����������� ����� child() - 
		//				������ ������� ������� � ������� ������� ��� ����������� ��������
		//				+ ������������ ��� ����� ������� � ���������� � ��������

		//������ ����������� ����������� ��������������� ������ ��� ���������� ����������

	{
		//������� ������ � ����-�� ���������� => "����-���� ��� �� ����, ��������, ���� � ���"
		//(�� ���� �� ����� ���� ��� ���� � ��� ����):


		std::shared_ptr<human> grandM1(new human("Eva1"));
		std::shared_ptr<human> grandF1(new human("Adam1"));
		std::shared_ptr<human> grandM2(new human("Eva2"));
		std::shared_ptr<human> grandF2(new human("Adam2"));
		//...

		//� ��� ��������� ���� - child():
		std::shared_ptr<human> father1 = human::child("Kain", grandM1, grandF1);
		std::shared_ptr<human> father2 = human::child("Avel", grandM1, grandF1);
		std::shared_ptr<human> mother1 = human::child("Alina", grandM2, grandF2);
		std::shared_ptr<human> mother2 = human::child("Jozel", grandM2, grandF2);
		//� � ����� � ���� ������� ���� ����:
		std::shared_ptr<human> people1 = human::child("Kain jr", mother1, father1 );
		std::shared_ptr<human> people2 = human::child("Bastard", mother2, father1);
		std::shared_ptr<human> people3 = human::child("Alsu", mother1, father1);

		std::shared_ptr<human> people4 = human::child("Ameli", mother2, father2);
		
		//...
		cout << endl << "_________________Alina's three__________________" << endl;
		mother1->print_three();

		cout << endl << "_________________Eva1's three__________________" << endl;
		grandM1->print_three();

		__asm nop
	}





	__asm nop

}
